package com.biz.primus.ms.member.service;

import com.biz.primus.common.utils.DateUtil;
import com.biz.primus.common.utils.DistanceCalc;
import com.biz.primus.model.member.exception.UserException;
import com.biz.primus.model.member.exception.UserExceptionType;
import com.biz.primus.model.member.enums.AddressTypes;
import com.biz.primus.model.member.vo.MemberAddressLabelVo;
import com.biz.primus.model.member.vo.MemberAddressVo;
import com.biz.primus.model.member.vo.request.MemberAddressCheckLabelNameRequestVo;
import com.biz.primus.model.member.vo.request.MemberAddressIdRequestVo;
import com.biz.primus.model.member.vo.request.MemberAddressNewRequestVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.member.dao.po.Member;
import com.biz.primus.ms.member.dao.po.MemberAddress;
import com.biz.primus.ms.member.dao.po.MemberAddressLabel;
import com.biz.primus.ms.member.dao.redis.MemberAddressLabelRedisDao;
import com.biz.primus.ms.member.dao.redis.MemberAddressRedisDao;
import com.biz.primus.ms.member.dao.repository.MemberAddressLabelRepository;
import com.biz.primus.ms.member.dao.repository.MemberAddressRepository;
import com.biz.primus.ms.member.dao.ro.MemberAddressLabelRo;
import com.biz.primus.ms.member.dao.ro.MemberAddressRo;
import com.biz.primus.ms.member.dao.ro.MemberRo;
import com.biz.primus.ms.member.trans.*;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 会员地址
 * @author jun.liu
 * @date 2017年10月23日
 * @reviewer
 * @see
 */
@Slf4j
@Service
public class MemberAddressService extends AbstractBaseService
{
    private final MemberAddressRedisDao memberAddressRedisDao;

    private final MemberAddressRepository memberAddressRepository;

    private final MemberAddressLabelRedisDao memberAddressLabelRedisDao;

    private final MemberAddressLabelRepository memberAddressLabelRepository;

    private final MemberService memberService;

    @Autowired
    public MemberAddressService(MemberAddressRedisDao memberAddressRedisDao, MemberAddressRepository memberAddressRepository,
                                        MemberAddressLabelRedisDao memberAddressLabelRedisDao, MemberAddressLabelRepository memberAddressLabelRepository,
                                        MemberService memberService)
    {
        this.memberAddressRedisDao = memberAddressRedisDao;
        this.memberAddressRepository = memberAddressRepository;
        this.memberAddressLabelRedisDao = memberAddressLabelRedisDao;
        this.memberAddressLabelRepository = memberAddressLabelRepository;
        this.memberService = memberService;
    }

    /**
     * 删除收货地址
     *
     * @return true: 删除收货地址成功, false: 删除收货地址失败
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteShippingAddress(MemberAddressVo reqVo)
    {
        log.debug("进行收货地址删除......");
        if (reqVo.getId() == null || reqVo.getId() == 0L)
        {
            throw new UserException(UserExceptionType.ID_ERROR);
        }
        MemberAddress po = memberAddressRepository.findOne(reqVo.getId());
        if (po == null)
        {
            throw new UserException(UserExceptionType.ADDRESS_NOT_EXIST);
        }
        deleteEntity(memberAddressRepository, memberAddressRedisDao, po.getId());
    }

    /**
     * 通过 ID以及userId 获取收货地址
     *
     * @param id
     * @return 收货地址 Vo
     */
    public MemberAddressVo getShippingAddressById(String id)
    {
        if (StringUtils.isBlank(id)) {
            return null;
        }
        MemberAddressRo ro = memberAddressRedisDao.findOne(Long.parseLong(id));
        if (ro == null) {
            log.info("收货地址不存在[{}]", id);
            return null;
        }
        return new MemberAddressRoToMemberAddressVo().apply(ro);
    }

    /**
     * 方法说明:设置地址类别
     *
     * @param userId    用户ID
     * @param addressId 收货地址ID
     * @return true: 设置家收货地址成功, false: 设置家收货地址失败
     */
    @Transactional(rollbackFor = Exception.class)
    public void setShippingAddressAlias(Long userId, Long addressId, AddressTypes addressType)
    {
        MemberAddress po = memberAddressRepository.findOne(addressId);
        if (po == null)
        {
            throw new UserException(UserExceptionType.ADDRESS_NOT_EXIST);
        }
        boolean flag = false;
        boolean isHomeOrComOrSchool = false;
        switch (addressType)
        {

            case school:
            case home:
            case company:
                flag = ifLabelNotExist(userId, addressType);
                isHomeOrComOrSchool = true;
                break;
            case NOLABEL:
            case other:
            default:
                flag = true;
                break;

        }
        if(flag)
        {
            MemberAddressLabel userAddressLabel = new MemberAddressLabel();
            userAddressLabel.setMemberId(userId);
            userAddressLabel.setLabelType(addressType);
            userAddressLabel.setLabelName(addressType.getDesc());
            saveOrUpdateUsingPoPKIncreament(memberAddressLabelRepository, memberAddressLabelRedisDao, userAddressLabel, new MemberAddressLabelToMemberAddressLabelRo());
        }
        // 如果当前修改的是家或者公司或者学校的地址 则需要把之前的老地址别名设置为 其它
        if (isHomeOrComOrSchool) {
            this.resetShippingAddressAliasHomeOrCompanyOrSchookToOther(addressType, userId);
            List<MemberAddressLabel> addressLabels = memberAddressLabelRepository.findByLabelTypeAndMemberId(addressType, userId);
            if (CollectionUtils.isNotEmpty(addressLabels) && addressLabels.get(0) != null) {
                po.setMemberrAddressLabelId(addressLabels.get(0).getId());
                po.setLabelName(addressLabels.get(0).getLabelName());
                po.setAddressType(addressLabels.get(0).getLabelType());
            }
        }
        saveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, po, new MemberAddressToMemberAddressRo());
    }

    /**
     * 判断标签是否存在
     * @param userId
     * @param type
     * @return
     */
    public boolean ifLabelNotExist(Long userId, AddressTypes type) {
        if (userId == null) {
            return true;
        }
        Member userInfo = memberService.findPoById(userId);
        if(userInfo == null)
        {
            throw new UserException(UserExceptionType.USER_NOT_EXIST);
        }
        /**判断地址是否存在*/
        List<MemberAddressLabelRo> userAddressLabelRos = memberAddressLabelRedisDao.findByMemberId(userId);
        if (CollectionUtils.isNotEmpty(userAddressLabelRos)) {
            for (MemberAddressLabelRo userAddressLabelRo : userAddressLabelRos) {
                if (userAddressLabelRo.getLabelType() != null && type.getValue() == userAddressLabelRo.getLabelType().getValue()) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 将老地址标签改为临时
     * @param addressAlias
     * @param userId
     */
    @Transactional(rollbackFor = Exception.class)
    public void resetShippingAddressAliasHomeOrCompanyOrSchookToOther(AddressTypes addressAlias, Long userId)
    {
        switch (addressAlias)
        {

            case school:
            case home:
            case company:
                break;
            case NOLABEL:
            case other:
            default:
                return;

        }
        List<MemberAddressRo> oldRos = memberAddressRedisDao.findAddressByAddressAlias(userId, addressAlias.getValue());
        if (CollectionUtils.isNotEmpty(oldRos)) {
            List<MemberAddress> pos = Lists.newArrayList();
            for (MemberAddressRo oldRo : oldRos) {
                MemberAddress oldPo = memberAddressRepository.findOne(oldRo.getId());
                oldPo.setAddressType(AddressTypes.NOLABEL);
                oldPo.setMemberrAddressLabelId(null);
                oldPo.setLabelName(AddressTypes.NOLABEL.getDesc());
                oldPo.setUpdateTimestamp(DateUtil.now());
                pos.add(oldPo);
            }
            batchSaveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, pos, new MemberAddressToMemberAddressRo());
        }
    }

    /**
     * 根据用户ID和地址ID设置该地址为默认地址
     *
     * @param userId
     * @param addressId
     */
    public void setDefaultAddress(Long userId, Long addressId) {
        // 获取当前收货地址
        MemberAddress po = memberAddressRepository.findOne(addressId);
        if (po == null) {
            throw new UserException(UserExceptionType.ADDRESS_NOT_EXIST);
        }
        List<MemberAddress> list = memberAddressRepository.listByUserIdDefaultAddress(userId);
        if (CollectionUtils.isNotEmpty(list)) {
            List<MemberAddress> pos = Lists.newArrayList();
            for (MemberAddress shippingAddress : list) {
                shippingAddress.setDefaultAddress(null);
                pos.add(shippingAddress);
            }
            batchSaveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, pos, new MemberAddressToMemberAddressRo());
        }
        // 设置为默认地址
        po.setDefaultAddress(true);
        saveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, po, new MemberAddressToMemberAddressRo());
    }

    /**
     * 方法说明:通过用户id查询所有收货地址
     *
     * @param userId 用户ID
     * @return
     */
    public List<MemberAddressVo> findAllShippingAddress(Long userId){
        List<MemberAddressRo> list = memberAddressRedisDao.findByUserId(userId);
        //过滤下经纬度不存在,省市id都不存在的
        Iterable<MemberAddressRo> filter = Iterables.filter(list, new Predicate<MemberAddressRo>() {
            @Override
            public boolean apply(MemberAddressRo input) {
                if (input == null || input.getLoginLat() == null ||  input.getLoginLon() == null
                        || input.getCityId() == null || input.getCityId() == 0
                        || input.getProvinceId() == null || input.getProvinceId() == 0) {
                    return false;
                }
                return true;
            }
        });
        return Lists.transform(Lists.newArrayList(filter), new MemberAddressRoToMemberAddressVo());
    }

    /**
     * 根据条件查询用户下所有的收货地址
     *
     * @return
     */
    public List<MemberAddressVo> findAllShippingAddressByCondition(Long userId, Integer limitDistance, BigDecimal lat, BigDecimal lon){
        if (userId == null || userId == 0L) {
            return Collections.emptyList();
        }
        if (lat == null || lon == null) {
            return this.findShippingAddressOrderByOrderTimeDesc(userId);
        } else {
            return this.findShippingAddressOrderByLocationDesc(userId, limitDistance, lat, lon);
        }
    }

    /**
     * 查询出用户收货地址并且按照下单时间先后排序
     *
     * @param userId
     * @return
     */
    public List<MemberAddressVo> findShippingAddressOrderByOrderTimeDesc(Long userId){
        if (userId == null) {
            return Collections.emptyList();
        }
        List<MemberAddressVo> shippingAddressVos = findAllShippingAddress(userId);
        if (CollectionUtils.isNotEmpty(shippingAddressVos)) {
            List<MemberAddressVo> result = Lists.newArrayList(shippingAddressVos);
            return result;
        }
        return Collections.emptyList();
    }

    /**
     * 查询用户收货地址并且按照经纬度排序
     *
     * @return
     */
    public List<MemberAddressVo> findShippingAddressOrderByLocationDesc(Long userId, Integer limitDistance, BigDecimal lat, BigDecimal lon){
        if (userId == null || lat == null || lon == null) {
            return Collections.emptyList();
        }

        return memberAddressRedisDao.findByUserId(userId).stream().map((MemberAddressRo input)->{
            BigDecimal addressLat = input.getLoginLat();
            BigDecimal addressLon = input.getLoginLon();
            Integer distance = Integer.MAX_VALUE;
            if (addressLat != null && addressLon != null) {
                distance = (int) DistanceCalc.distance(lat.doubleValue(),
                        lon.doubleValue(), addressLat.doubleValue(), addressLon.doubleValue());
            }
            return new AddressDistancePackage(distance, input);
        }).sorted().filter((AddressDistancePackage input)->{
            MemberAddressRo ro = input.ro;
            // 过滤详细地址和城市ID为空的地址
            if (ro == null || StringUtils.isBlank(ro.getDetailAddress()) || ro.getCityId() == null
                    || ro.getCityId() == 0 || ro.getProvinceId() == null || ro.getProvinceId() == 0
                    || StringUtils.isBlank(ro.getDetailAddress().replace("\"", ""))) {
                return false;
            }
            if (limitDistance == null) {
                return true;
            } else {
                return input.distance < limitDistance;
            }
        }).map(AddressDistancePackage::toVo)
                //按照距离升序排列
                .sorted(Comparator.comparing(MemberAddressVo::getDistance,Comparator.naturalOrder()))
                .collect(Collectors.toList());

    }

    /**
     * 辅助findShippingAddressOrderByLocationDesc方法排序
     */
    private class AddressDistancePackage implements Comparable<AddressDistancePackage> {
        private Integer distance;
        private MemberAddressRo ro;
        AddressDistancePackage(Integer distance, MemberAddressRo ro) {
            super();
            this.distance = distance;
            this.ro = ro;
        }
        MemberAddressVo toVo() {
            MemberAddressVo addressNewVo = new MemberAddressRoToMemberAddressVo().apply(ro);
            addressNewVo.setDistance(distance);
            return addressNewVo;
        }
        @Override
        public int compareTo(AddressDistancePackage o) {
            return o.distance.compareTo(this.distance);
        }
    }

    /**
     * 方法说明:根据百度地理名称获取省份信息
     *
     * @param baiduName 百度地理名称 必须传入，不能为null或者是“”
     * @return 省份vo
     */
//    public ProvinceResponseVo findProvinceByBaiduName(String baiduName) {
//        return this.geoService.findProvinceByBaiduName(baiduName);
//    }

    /**
     * 方法说明:根据百度地理名称获取城市信息
     *
     * @param baiduName 百度地理名称 必须传入，不能为null或者是“”
     * @return 城市vo
     */
//    public CityResponseVo findCityByBadiuName(String baiduName) {
//        return this.geoService.findCityByBadiuName(baiduName);
//    }

    /**
     * 方法说明:根据百度地理名称查询区县信息
     *
     * @param baiduName 百度地理名称 必须传入，不能为null或者是“”
     * @return 区县vo
     */
//    public DistrictResponseVo findDistrictByBaiduName(String baiduName) {
//        return this.geoService.findDistrictByBaiduName(baiduName);
//    }

    /**
     * 根据userID和收货地址类别获取收货地址
     */
    public List<MemberAddressVo> getShippingAddress(Long userId, AddressTypes alias)
    {
        List<MemberAddressRo> addressByAddressalias = memberAddressRedisDao.findAddressByAddressAlias(userId, alias.getValue());
        return Lists.transform(addressByAddressalias, new MemberAddressRoToMemberAddressVo());
    }

    /**
     * 获取各个省份信息，并且将所有的省份信息按照前缀（prefix）分组封装成vo并返回
     *
     * @return 省份信息vo
     */
//    public List<ProvincesItemResponseVo> getProvinces() {
//        return this.geoService.getProvinces();
//    }

    /**
     * 更新或保存地址标签
     * 标签名重复时会抛出异常
     */
    public void saveOrUpdateLabel(MemberAddressCheckLabelNameRequestVo reqVo)
    {
        if (reqVo == null || reqVo.getLabelType() == null || StringUtils.isBlank(reqVo.getLabelName()))
        {
            throw new UserException(UserExceptionType.PARAMS_ERROR);
        }
        MemberRo memberRo = this.memberService.findRoById(reqVo.getGp().getMemberId());
        MemberAddressLabelRo ro = memberAddressLabelRedisDao.findByMemberAndLabelName(memberRo.getId(), reqVo.getLabelName());
        if (ro == null) {
            ro = new MemberAddressLabelRo();
            ro.setLabelName(reqVo.getLabelName());
            ro.setMemberId(memberRo.getId());
            if (reqVo.getLabelType() != null) {
                ro.setLabelType(reqVo.getLabelType());
            }
        } else {
            //标签名重复
            throw new UserException(UserExceptionType.ADDRESS_LABEL_REPEAT);
            //以前的代码逻辑

//            if (Objects.equals(ro.getLabelType().getValue(), AddressTypes.home.getValue())
//                    || Objects.equals(ro.getLabelType().getValue(), AddressTypes.company.getValue())) {
//                throw new BizBusinessException("home and company do not update");
//            }
//            ro.setLabelName(reqVo.getLabelName());
//            ro.setMemberId(memberRo.getId());
//            if (reqVo.getLabelType() != null) {
//                ro.setLabelType(reqVo.getLabelType());
//            }
//            ro.setUpdateTimestamp(DateUtil.now());
        }
        MemberAddressLabel po = new MemberAddressLabel();
        BeanUtils.copyProperties(ro, po);
        saveOrUpdateUsingPoPKIncreament(memberAddressLabelRepository, memberAddressLabelRedisDao, po, new MemberAddressLabelToMemberAddressLabelRo());
    }

    /**
     * 获取用户所有的标签
     */
    public List<MemberAddressLabelVo> getAllUserLabel(Long memberId)
    {
        List<MemberAddressLabelRo> ros = memberAddressLabelRedisDao.findByMemberId(memberId);
        return Lists.transform(ros, new MemberAddressLabelRoToMemberAddressLabelVo());
    }

    /**
     * 删除标签
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteLabelNew(MemberAddressIdRequestVo reqVo)
    {
        MemberAddressLabelRo ro = memberAddressLabelRedisDao.findOne(reqVo.getId());
        if(ro == null)
        {
            throw new UserException(UserExceptionType.LABEL_NOT_EXIST);
        }
        if (Objects.equals(ro.getLabelType(), AddressTypes.home.getValue())
                || Objects.equals(ro.getLabelType(), AddressTypes.company.getValue())) {
            throw new UserException(UserExceptionType.HOME_COMPANY_CANT_DEL);
        }
        List<MemberAddress> pos = memberAddressRepository.findByMemberrAddressLabelId(ro.getId());
        if (CollectionUtils.isNotEmpty(pos)) {
            for (MemberAddress address : pos) {
                address.setMemberrAddressLabelId(null);
                address.setAddressType(AddressTypes.NOLABEL);
            }
        }
        batchSaveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, pos, new MemberAddressToMemberAddressRo());
        MemberAddressLabel po = new MemberAddressLabel();
        BeanUtils.copyProperties(ro, po);
        saveOrUpdateUsingPoPKIncreament(memberAddressLabelRepository, memberAddressLabelRedisDao, po, new MemberAddressLabelToMemberAddressLabelRo());
    }

    /**
     * 保存或更新收货地址
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateAddress(MemberAddressVo reqVo)
    {
        if (reqVo == null)
        {
            throw new UserException(UserExceptionType.PARAMS_ERROR);
        }
        MemberRo memberRo = this.memberService.findRoById(reqVo.getMemberId());
        List<MemberAddress> savePos = Lists.newArrayList();
        MemberAddress po = null;
        if(reqVo.getId() == null  || reqVo.getId() == 0L)
        {
            po = new MemberAddress();
            BeanUtils.copyProperties(reqVo, po);
        }
        else
        {
            po = memberAddressRepository.findOne(reqVo.getId());
        }
        savePos.add(po);
        // 如果当前修改的是家或者公司的地址 则需要把之前的老地址别名设置为 其它
        if (Objects.equals(po.getAddressType().getValue(), AddressTypes.home.getValue())
                || Objects.equals(po.getAddressType().getValue(), AddressTypes.company.getValue())
                || Objects.equals(po.getAddressType().getValue(), AddressTypes.school.getValue()))
        {
            List<MemberAddress> tempPos = memberAddressRepository.findByMemberIdAndAddressType(memberRo.getId(), po.getAddressType());
            if(tempPos != null && !tempPos.isEmpty())
            {
                MemberAddress upPo = tempPos.get(0);
                upPo.setAddressType(AddressTypes.NOLABEL);
                upPo.setLabelName(AddressTypes.NOLABEL.getDesc());
                upPo.setMemberrAddressLabelId(null);
                upPo.setUpdateTimestamp(DateUtil.now());
                savePos.add(upPo);
            }
        }
        batchSaveOrUpdateUsingPoPKIncreament(memberAddressRepository, memberAddressRedisDao, savePos, new MemberAddressToMemberAddressRo());
    }

    /**
     * 删除收货地址
     */
    public void deleteAddressNew(MemberAddressIdRequestVo reqVo)
    {
        deleteEntity(memberAddressRepository, memberAddressRedisDao, reqVo.getId());
    }

    /**
     * 获取所有收货地址
     */
    public List<MemberAddressVo> getAllAddress(MemberAddressNewRequestVo reqVo)
    {
        List<MemberAddress> pos = memberAddressRepository.findByMemberId(reqVo.getMemberId());
        //过滤下经纬度不存在,省市id都不存在的
        Iterable<MemberAddress> filter = Iterables.filter(pos, new Predicate<MemberAddress>() {
            @Override
            public boolean apply(MemberAddress input) {
                if (input == null || input.getLoginLat()== null ||  input.getLoginLon() == null
                        || input.getCityId() == null || input.getCityId() == 0
                        || input.getProvinceId() == null || input.getProvinceId() == 0) {
                    return false;
                }
                return true;
            }
        });
        return Lists.transform(pos, new MemberAddressToMemberAddressVo());
    }

    /**
     * 获取所有收货地址
     */
    public List<MemberAddressVo> getAllAddress(Long memberId)
    {
        List<MemberAddress> pos = memberAddressRepository.findByMemberId(memberId);
        //过滤下经纬度不存在,省市id都不存在的
        Iterable<MemberAddress> filter = Iterables.filter(pos, new Predicate<MemberAddress>() {
            @Override
            public boolean apply(MemberAddress input) {
                if (input == null || input.getLoginLat()== null ||  input.getLoginLon() == null
                        || input.getCityId() == null || input.getCityId() == 0
                        || input.getProvinceId() == null || input.getProvinceId() == 0) {
                    return false;
                }
                return true;
            }
        });
        return Lists.transform(pos, new MemberAddressToMemberAddressVo());
    }

    /**
     * 创建会员默认收获地址标签  --- 家和公司
     */
    @Transactional
    public void initAddressLabel(Long memberId) {
//        Member member = this.findPoById(memberId);
//        if (member == null) {
//            throw new UserException(UserExceptions.USER_NOT_EXIST);
//        }
        List<MemberAddressLabel> labels =  Lists.newArrayList();
        MemberAddressLabel home = new MemberAddressLabel();
        home.setLabelType(AddressTypes.home);
        home.setLabelName(AddressTypes.home.getDesc());
        home.setMemberId(memberId);
        labels.add(home);
        MemberAddressLabel company = new MemberAddressLabel();
        company.setLabelType(AddressTypes.company);
        company.setLabelName(AddressTypes.company.getDesc());
        company.setMemberId(memberId);
        labels.add(company);
        batchSaveOrUpdateUsingPoPKIncreament(memberAddressLabelRepository,memberAddressLabelRedisDao,labels,new MemberAddressLabelToMemberAddressLabelRo());
    }


}
